package chains

import (
	"context"
	"fmt"
	"xagent/internal/memory"
	"xagent/internal/tools"
)

// Chain represents a sequence of operations that can be executed
type Chain interface {
	// Execute executes the chain with the given input
	Execute(ctx context.Context, input interface{}) (interface{}, error)

	// Name returns the name of the chain
	Name() string

	// Description returns a description of what the chain does
	Description() string
}

// BaseChain provides common functionality for chains
type BaseChain struct {
	name        string
	description string
	tools       *tools.ToolManager
	memory      memory.MemoryManager
}

// NewBaseChain creates a new base chain
func NewBaseChain(name, description string, tools *tools.ToolManager, memory memory.MemoryManager) *BaseChain {
	return &BaseChain{
		name:        name,
		description: description,
		tools:       tools,
		memory:      memory,
	}
}

// Name implements Chain
func (c *BaseChain) Name() string {
	return c.name
}

// Description implements Chain
func (c *BaseChain) Description() string {
	return c.description
}

// ChainManager manages the available chains
type ChainManager struct {
	chains map[string]Chain
}

// NewChainManager creates a new chain manager
func NewChainManager() *ChainManager {
	return &ChainManager{
		chains: make(map[string]Chain),
	}
}

// RegisterChain registers a new chain
func (m *ChainManager) RegisterChain(chain Chain) {
	m.chains[chain.Name()] = chain
}

// GetChain gets a chain by name
func (m *ChainManager) GetChain(name string) Chain {
	return m.chains[name]
}

// ListChains lists all available chains
func (m *ChainManager) ListChains() []Chain {
	chains := make([]Chain, 0, len(m.chains))
	for _, chain := range m.chains {
		chains = append(chains, chain)
	}
	return chains
}

// ExecuteChain executes a chain by name
func (m *ChainManager) ExecuteChain(ctx context.Context, name string, input interface{}) (interface{}, error) {
	chain := m.GetChain(name)
	if chain == nil {
		return nil, fmt.Errorf("chain not found: %s", name)
	}
	return chain.Execute(ctx, input)
}
